package org.visionlibrary.image.filters.thresholding;

import java.awt.Point;

import javax.media.jai.TiledImage;

import org.visionlibrary.image.model.WindowFilter;

/*
 * Sauvola recommends K_VALUE = 0.5 and R_VALUE = 128.
 * This is a modification of Niblack's thresholding method.
 *
 * Sauvola J. and Pietaksinen M. (2000) "Adaptive Document Image Binarization"
 * Pattern Recognition, 33(2): 225-236
 * http://www.ee.oulu.fi/mvg/publications/show_pdf.php?ID=24
 */
public class SimpleSauvolaThreshold extends WindowFilter {
	protected int width = 9;
	protected int height = 9;
	protected double k = 0.5;
	protected double r = 128;

	protected int foreground = 255; // foreground pixel value (default 0)
	protected int background = 0; // background pixel value (default 255 for
									// 8bpc image)

	public SimpleSauvolaThreshold() {
		this(9,9,0.5,128);
	}
	
	public SimpleSauvolaThreshold(int width,
			int height, double k, double r,
			int foreground, int background) {
		this.width = width;
		this.height = height;
		this.k = k;
		this.r = r;
		this.foreground = foreground;
		this.background = background;
	}
	
	public SimpleSauvolaThreshold(int width, int height, 
								  double k, double r) {
		this.width = width;
		this.height = height;
		this.k = k;
		this.r = r;
	}

	@Override
	protected int getNewPixelVal(TiledImage src, Point p, int channel) {
		int sum = 0, sum_sqr = 0; // temp variables used in the calculation of
									// local mean and variances
		double local_mean = 0; // gray level mean in a particular window
								// position
		double local_var = 0; // gray level variance in a particular window
								// position */

		// used per channel model in library but if filter will be used only for
		// gray scale images
		// it wont be a problem,
		// count sum of pixel values and sum of squares
		Point pIter = new Point();
		for (pIter.y = 0; pIter.y < windowHeight; pIter.y++)
			for (pIter.x = 0; pIter.x < windowWidth; pIter.x++) {
				int val = getWindowPixelVal(src, pIter, channel);
				sum += val;
				sum_sqr += val * val;
			}

		// count local mean (for desired window)
		local_mean = (double)sum / (double)(windowHeight * windowWidth);
		// count local variance
		local_var = ((double)sum_sqr / (double)(windowHeight * windowWidth))
				- local_mean * local_mean;

		// count local threshold
		double threshold = local_mean
				* (1.0 + k * ((Math.sqrt(local_var) / r) - 1.0));

		// return proper values
		return ((getWindowPixelVal(src, dstPointInWindow, channel) > threshold) ? foreground
				: background);
	}

	@Override
	protected void setWindowProperties() {
		windowWidth = width;
		windowHeight = height;
		dstPointInWindow = new Point(width / 2, height / 2);
	}
}
